package cn.liuxiany.alibaba.consumer.controller;

import cn.liuxiany.alibaba.common.request.Result;
import cn.liuxiany.alibaba.provider.api.HelloService;
//import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 其中@Reference是在org.apache.dubbo.config.annotation下
 *
 * @author liuxiany
 * @date 2020/07/04
 */
@Slf4j
@RestController
@RequestMapping("demo")
public class DemoController {

    private static final String X_REQUEST_IP = "X-Request-Id";// nginx需要配置

    /**
     * loadbalance:
     * 负载均衡默认为random
     * random - 随机;
     * roundrobin - 轮询;
     * leastactive - 最少活跃调用;
     * consistenthash - 哈希一致 (2.1.0以上版本);
     * shortestresponse - 最短响应 (2.7.7以上版本);
     * <p>
     * mock: 服务降级
     * 可以是mock类的全限定路径，也可以是true。当是true时，需要在相同包下有类名 + Mock后缀的实现类。
     * <p>
     * check为false时，启动时不检查服务是否可用
     */
//    @DubboReference(loadbalance = "roundrobin", timeout = 5000, check = false)
    @DubboReference(loadbalance = "roundrobin", timeout = 5000, check = false, mock = "cn.liuxiany.alibaba.provider.mock.HelloServiceMock")
    private HelloService helloService;

    @Value("${spring.application.name}")
    private String appName;

    @Value("${server.port}")
    private String port;

//    @CircuitBreaker(name = "helloWorld", fallbackMethod = "testFallback")
    @GetMapping(value = "/test/{name}")
    public String test(@PathVariable String name) {
        log.info("this is {}:{}", appName, port);
//        return helloService.hello(String.format("hello:%s, this is %s:%s", name, appName, port));
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
//        log.info("requestId is {}", request.getHeader(X_REQUEST_IP));

        // 在consumer、provider之间传递参数
        // 一定要在方法调用之前进行set
        RpcContext.getContext().setAttachment(X_REQUEST_IP, request.getHeader(X_REQUEST_IP));

        String result = null;
        // try之后 全局异常处理照样能捕捉到
        try {
            result = helloService.hello(name);
            log.info("this is result :{}", result);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 获得来自provider的参数
        String hello = RpcContext.getServerContext().getAttachment("hello");
        log.info("result from provider:{}", hello);

        return result;
    }

    /*public String testFallback(java.lang.Throwable throwable) {

        return "不带参数的fallback";
    }

    public String testFallback(io.github.resilience4j.circuitbreaker.CallNotPermittedException callNotPermittedException) {

        return "CallNotPermittedException拉拉拉";
    }

    public String testFallback(java.lang.Throwable throwable, String name) {

        return "带参数的fallback" + name;
    }*/

    @GetMapping(value = "/test/break")
    public String testBreak(Integer id) {
        log.info("进入testBreak");

        if (id <= 0) {
            // 模拟异常
            try {
                String s = null;
                String b = s.substring(0);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
//            int i = 10 / 0;
        } else if (id % 2 == 0) {
            // 模拟超时
            // try之后 全局异常处理依旧能捕捉的到
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            // 正常请求
            return "哈哈！";
        }

        return "呵呵！";
    }

    /**
     * 测试获取traceId
     *
     * @param request
     * @return
     */
    @GetMapping("test/traceId")
    public String traceIdTest(HttpServletRequest request) {
        String traceId = request.getHeader(X_REQUEST_IP);

        return traceId;
    }

    /**
     * 测试获取traceId
     *
     * @return
     */
    @GetMapping("test/consumer")
    public Result<String> traceConsumer() {


        return Result.success("这里是consumer啊");
    }

    /**
     * 测试获取traceId
     *
     * @return
     */
    @GetMapping("test2/consumer2")
    public Result<String> traceConsumer2(int id) {

        System.out.println("id:" + id);

        Assert.isTrue(id % 2 == 0, "必须偶数assert啊啊啊");

        return Result.success("这里是consumer22222啊");
    }
}
